package com.yuxl.admin.manager.auth.server.controller;

import com.yuxl.admin.manager.auth.core.dataLoader.UserRoleDataLoader;
import com.yuxl.admin.manager.auth.core.entity.AuthRole;
import com.yuxl.admin.manager.auth.core.entity.AuthUser;
import com.yuxl.admin.manager.auth.core.service.AuthRoleService;
import com.yuxl.admin.manager.auth.core.service.AuthUserService;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dataloader.BatchLoaderEnvironment;
import org.dataloader.DataLoader;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.MutationMapping;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.graphql.data.method.annotation.SchemaMapping;
import org.springframework.graphql.execution.BatchLoaderRegistry;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;

/**
 * GraphQL用户控制器
 * 处理与用户相关的GraphQL查询和变更
 */
@Slf4j
@Controller
@RequiredArgsConstructor
public class GraphQLUserController {

    private final AuthUserService authUserService;
    private final PasswordEncoder passwordEncoder;
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private final UserRoleDataLoader userRoleDataLoader;
    private final BatchLoaderRegistry batchLoaderRegistry;


    @PostConstruct
    public void init() {
        batchLoaderRegistry.forTypePair(Long.class, List.class)
                .registerBatchLoader((List<Long> userIds, BatchLoaderEnvironment environment) ->
                        userRoleDataLoader.apply(userIds, environment).flatMapMany(Flux::fromIterable));
    }
    /**
     * 根据ID查询用户
     * @param id 用户ID
     * @return 用户信息
     */
    @QueryMapping
    public Mono<AuthUser> user(@Argument Long id) {
        // 调用authUserService的findById方法查找用户
        return authUserService.findById(id);
    }

    /**
     * 分页查询用户
     * @param page 页码
     * @param size 每页大小
     * @return 分页后的用户列表
     */
    @QueryMapping
    public Flux<AuthUser> users(@Argument Integer page, @Argument Integer size) {
        // 调用authUserService的findAll方法，传入分页参数
        return authUserService.findAll(page, size);
    }

    /**
     * 根据用户名查询用户
     * @param username 用户名
     * @return 匹配的用户列表
     */
    @QueryMapping
    public Mono<AuthUser> usersByUsername(@Argument String username) {
        // 调用authUserService的findByUsername方法查找用户
        return authUserService.findByUsername(username);
    }

    /**
     * 根据ID或用户名查找用户
     * @param id 用户ID
     * @param username 用户名
     * @return 匹配的用户信息
     */
    @QueryMapping
    public Mono<AuthUser> findUser(@Argument Long id, @Argument String username) {
        if (id != null) {
            // 如果提供了ID，则根据ID查找
            return authUserService.findById(id);
        } else if (username != null) {
            // 如果提供了用户名，则根据用户名查找
            return authUserService.findByUsername(username);
        }
        // 如果既没有提供ID也没有提供用户名，则返回空
        return Mono.empty();
    }

    /**
     * 搜索用户
     * @param username 用户名（可选）
     * @param startTime 开始时间（可选）
     * @param endTime 结束时间（可选）
     * @param page 页码（可选）
     * @param size 每页大小（可选）
     * @return 搜索结果，包含用户列表和总数
     */
    @QueryMapping
    public Mono<Map<String, Object>> searchUsers(@Argument String username, 
                                                 @Argument String startTime, 
                                                 @Argument String endTime, 
                                                 @Argument Integer page, 
                                                 @Argument Integer size) {
        // 将字符串时间转换为LocalDateTime对象
        LocalDateTime start = startTime != null ? LocalDateTime.parse(startTime, formatter) : null;
        LocalDateTime end = endTime != null ? LocalDateTime.parse(endTime, formatter) : null;
        
        // 调用authUserService的searchUsers方法搜索用户
        return authUserService.searchUsers(username, start, end, page, size)
                .collectList()
                .zipWith(authUserService.countUsers(username, start, end))
                .map(tuple -> Map.of(
                        "users", tuple.getT1(),
                        "totalCount", tuple.getT2()
                ))
                .doOnSuccess(result -> log.debug("Search result: {}", result))
                .onErrorResume(e -> {
                    // 如果发生错误，记录错误并返回空结果
                    log.error("Error in searchUsers", e);
                    return Mono.just(Map.of(
                            "users", List.of(),
                            "totalCount", 0
                    ));
                });
    }

    /**
     * 统计用户数量
     * @param username 用户名（可选）
     * @param startTime 开始时间（可选）
     * @param endTime 结束时间（可选）
     * @return 用户数量
     */
    @QueryMapping
    public Mono<Long> userCount(@Argument String username, 
                                @Argument String startTime, 
                                @Argument String endTime) {
        // 将字符串时间转换为LocalDateTime对象
        LocalDateTime start = startTime != null ? LocalDateTime.parse(startTime, formatter) : null;
        LocalDateTime end = endTime != null ? LocalDateTime.parse(endTime, formatter) : null;
        
        // 调用authUserService的countUsers方法统计用户数量
        return authUserService.countUsers(username, start, end);
    }

    /**
     * 创建新用户
     * @param input 用户输入数据
     * @return 创建的用户信息
     */
    @MutationMapping
    public Mono<AuthUser> createUser(@Argument AuthUser input) {
        // 调用authUserService的createUser方法创建新用户
        input.setPassword(passwordEncoder.encode(input.getPassword()));
        return authUserService.createUser(input);
    }

    /**
     * 更新用户信息
     * @param id 用户ID
     * @param input 更新的用户数据
     * @return 更新后的用户信息
     */
    @MutationMapping
    public Mono<AuthUser> updateUser(@Argument Long id, @Argument AuthUser input) {
        // 调用authUserService的updateUser方法更新用户信息
        return authUserService.updateUser(id, input);
    }

    /**
     * 删除用户
     * @param id 要删除的用户ID
     * @return 删除操作是否成功
     */
    @MutationMapping
    public Mono<Boolean> deleteUser(@Argument Long id) {
        // 调用authUserService的deleteUser方法删除用户
        return authUserService.deleteUser(id);
    }

    /**
     * 为用户分配角色
     * @param userId 用户ID
     * @param roleId 角色ID
     * @return 分配操作是否成功
     */
    @MutationMapping
    public Mono<Boolean> assignRoleToUser(@Argument Long userId, @Argument Long roleId) {
        // 调用authUserService的assignRoleToUser方法为用户分配角色
        return authUserService.assignRoleToUser(userId, roleId);
    }

    /**
     * 获取用户的角色列表
     * @param user 用户对象
     * @return 用户拥有的角色列表
     */
    @SchemaMapping(typeName = "User", field = "roles")
    public Mono<List<AuthRole>> roles(AuthUser user, DataLoader<Long, List<AuthRole>> dataLoader) {
        return Mono.fromFuture(dataLoader.load(user.getId()));
    }
}